package com.genokon.route;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * @author by baichaoda
 * @Date 2020/7/23 15:38
 */
@Component
public class NacosDynamicRoutingService implements ApplicationEventPublisherAware {
    private final Logger logger = LoggerFactory.getLogger(NacosDynamicRoutingService.class);
    private static final String DATA_ID = "gateway-router";
    private static final String GROUP = "DEFAULT_GROUP";

    @Value("${spring.cloud.nacos.config.server-addr}")
    private String serverAddr;

    private final RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher applicationEventPublisher;

    private static final List<String> ROUTE_LIST = new ArrayList<>();

    @Autowired
    public NacosDynamicRoutingService(RouteDefinitionWriter routeDefinitionWriter){
        this.routeDefinitionWriter = routeDefinitionWriter;
    }

    @PostConstruct
    public void dynamicRouteByNacosListener(){
        try {
            ConfigService configService = NacosFactory.createConfigService(serverAddr);
            configService.getConfig(DATA_ID, GROUP, 5000);
            configService.addListener(DATA_ID, GROUP, new Listener() {
                @Override
                public Executor getExecutor() {
                    return null;
                }

                @Override
                public void receiveConfigInfo(String s) {
                    logger.info(s);
                    cleanRoute();
                    try {
                        List<RouteDefinition> gatewayRouteDefinition = JSONObject.parseArray(s, RouteDefinition.class);
                        gatewayRouteDefinition.forEach(item->addRoute(item));
                        publish();
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            });
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void setApplicationEventPublisher(@NonNull ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    /**
     * 发布route
     */
    public void publish(){
        this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
        logger.info("publish....");
    }

    /**
     * 新增route
     * @param routeDefinition route定义
     */
    public void addRoute(RouteDefinition routeDefinition){
        try {
            routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
            ROUTE_LIST.add(routeDefinition.getId());
            logger.info("add route .....");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    /**
     * 清理route
     */
    public void cleanRoute(){
        ROUTE_LIST.forEach(id-> this.routeDefinitionWriter.delete(Mono.just(id)).subscribe());
        ROUTE_LIST.clear();
        logger.info("clean route ....");
    }
}
